﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace SGCG.Model
{
    public class FloodPainter
    {

        private class FakeCanvasClass : IDrawingCanvas
        {
            public FakeCanvasClass(FloodPainter painter)
            {
                this.painter = painter;
            }

            public void SetPixel(int x, int y, Color color)
            {
                SetPixel(x, y, 255, 255, 255, 255);
            }

            public void SetPixel(int x, int y, byte alpha, byte r, byte g, byte b)
            {
                painter.borderPoints.Add(new IntPoint() { X = x, Y = y });
            }

            public void SendRedrawRequest()
            {
                throw new NotImplementedException();
            }

            public int GetWidth()
            {
                throw new NotImplementedException();
            }

            public int GetHeight()
            {
                throw new NotImplementedException();
            }

            FloodPainter painter;
        }

        // ... struct?
        private class IntPoint
        {
            public int X { get; set; }
            public int Y { get; set; }
        }

        public FloodPainter(int width, int height)
        {
            this.width = width;
            this.height = height;
            //this.painted = new bool[width, height];
            //for (int i = 0; i < 2000; ++i)
            //    for (int j = 0; j < 2000; ++j)
            //        painted[i, j] = false;
            borderPoints = new List<IntPoint>();
        }

        //private static int[] dx = new int[] { 1, 0, -1, 0 };
        //private static int[] dy = new int[] { 0, 1, 0, -1 };
        private static int[] x  = new int[2000 * 2000];
        private static int[] y  = new int[2000 * 2000];
        public void Draw(int initX, int initY)
        {
            if (borderPoints.Count == 0) return;
            int minx = int.MaxValue, miny = int.MaxValue;
            int maxx = int.MinValue, maxy = int.MinValue;
            foreach (var item in borderPoints)
            {
                minx = Math.Min(minx, item.X);
                miny = Math.Min(miny, item.Y);
                maxx = Math.Max(maxx, item.X);
                maxy = Math.Max(maxy, item.Y);
            }
            for (int i = 0; i <= maxx - minx; ++i)
                for (int j = 0; j <= maxy - miny; ++j)
                    painted[i, j] = false;
            foreach (var item in borderPoints)
            {
                painted[item.X-minx, item.Y-miny] = true;
            }
            initX -= minx;
            initY -= miny;

            int stkp = 0;
            x[stkp] = initX;
            y[stkp] = initY;
            ++stkp;
            int xx, yy, nx, ny;
            while (stkp != 0)
            {
                --stkp;
                xx = x[stkp];
                yy = y[stkp];
                if (painted[xx, yy])
                    continue;
                painted[xx, yy] = true;
                Paint(xx + minx, yy + miny);

                nx = xx + 1;
                ny = yy;
                if (!painted[nx, ny])
                {
                    x[stkp] = nx;
                    y[stkp] = ny;
                    ++stkp;
                }
                nx = xx;
                ny = yy + 1;
                if (!painted[nx, ny])
                {
                    x[stkp] = nx;
                    y[stkp] = ny;
                    ++stkp;
                }
                nx = xx - 1;
                ny = yy;
                if (!painted[nx, ny])
                {
                    x[stkp] = nx;
                    y[stkp] = ny;
                    ++stkp;
                }
                nx = xx;
                ny = yy - 1;
                if (!painted[nx, ny])
                {
                    x[stkp] = nx;
                    y[stkp] = ny;
                    ++stkp;
                }
            }
        }

        private bool IsValid(int x, int y)
        {
            return x >= 0 && y >= 0 && x < width && y < height;
        }

        private void Paint(IntPoint p)
        {
            Paint(p.X, p.Y);
        }

        private void Paint(int x, int y)
        {
            DrawingCanvas.SetPixel(x, y, Texture.GetColorAt(x, y));
        }

        private IDrawingCanvas fakeCanvas;
        public IDrawingCanvas FakeCanvas
        {
            get
            {
                if (fakeCanvas == null)
                    fakeCanvas = new FakeCanvasClass(this);
                return fakeCanvas;
            }
        }

        public IDrawingCanvas DrawingCanvas { get; set; }

        public ITexture Texture { get; set; }

        private static bool[,] painted = new bool[2000, 2000];
        int width, height;
        private List<IntPoint> borderPoints;

    }
}
